﻿//2013/3/12,todo: 昨天改了发送，需要继续改接收处理的逻辑
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebUI.Models;
using System.Data.Objects;

namespace WebUI.Services
{
    public class SmsSessionSvc : IDisposable
    {

        protected static System.Threading.ReaderWriterLockSlim Locker = new System.Threading.ReaderWriterLockSlim();
        protected static SmsSessionSvc _Instance;
        public static SmsSessionSvc Instance
        {
            get
            {
                if (null == _Instance)
                {
                    lock (Locker)
                    {
                        if (null == _Instance)
                        {
                            _Instance = new SmsSessionSvc();
                        }
                    }
                }
                return _Instance;
            }

        }
        public System.Timers.Timer SmsSendTimer { get; private set; }
        public System.Timers.Timer SmsReadAndProcTimer { get; private set; }

        public int TaskHour { get; set; }
        public bool Debug_IsLog { get; set; }
        public bool Debug_IsMocking { get; set; }
        public DateTime Debug_MockNowValue { get; set; }
        public string[] Debug_MockUserNames { get; set; }

        #region Logs
        public string LogString { get; set; }

        public void Log(Func<object> func)
        {
            if (Debug_IsLog)
            {
                Log(func.Invoke().ToString());
            }
        }
        public void Log(Func<IEnumerable<string>> func)
        {
            if (Debug_IsLog)
            {
                Log(func.Invoke().ToArray());
            }
        }

        public void Log<T>(Func<IEnumerable<T>> func)
        {
            if (Debug_IsLog)
            {
                Log(func.Invoke().Cast<string>().ToArray());
            }
        }

        public void Log(params string[] msg)
        {
            if (Debug_IsLog)
            {
                //System.Environment.StackTrace
                LogString += string.Format("{0:dd日 HH:mm:ss.fff}\t {1}\r\n", DateTime.Now, string.Join(" , ", msg));
            }
            WebUI.MvcApplication.Log(msg);
        }
        #endregion logs

        //每天TaskHour点开始发送短信。初始化时定为20点。如果现在不到8点，则在今天8点，否则，如果超过8:0:0 则到明天8点。
        public void ResetSenderTimer(int hour)
        {
            DateTime nextActTime = DateTime.Today.AddHours(hour);

            DateTime now = DateTime.Now;
            if (DateTime.Now >= nextActTime) nextActTime = nextActTime.AddDays(1);


            TimeSpan ts = nextActTime - now;
            //TimeSpan ts = (DateTime.Today.AddHours(hour).AddDays(((hour < DateTime.Now.Hour) ? 1 : 0)) - DateTime.Now);
            SmsSendTimer.Interval = ts.TotalMilliseconds;
            NextSendingTime = DateTime.Now.Add(ts);
        }
        public DateTime NextSendingTime = DateTime.MaxValue;
        public DateTime NextReadingTime = DateTime.MaxValue;

        public TimeSpan Hour24 = new TimeSpan(24, 0, 0);
        protected SmsSessionSvc()
        {
            // 发送短信 默认每天制定时间运行一次，第一次，设定在下一个Task Hour--(例如8点)运行。
            SmsSendTimer = new System.Timers.Timer();
            ResetSenderTimer(20);

            //处理短信 随时 执行。
            SmsReadAndProcTimer = new System.Timers.Timer(1000 * double.Parse(System.Configuration.ConfigurationManager.AppSettings["SmsReadAndProcTimerIntervalSec"]));

            SmsSendTimer.Elapsed += new System.Timers.ElapsedEventHandler(SmsSendTimer_Elapsed);
            SmsReadAndProcTimer.Elapsed += new System.Timers.ElapsedEventHandler(SmsReadAndProcTimer_Elapsed);
        }

        public void StartTimers(int taskhour)
        {
            ResetSenderTimer(taskhour);
            SmsReadAndProcTimer.Start();
            SmsSendTimer.Start();

            SmsSendTimer.Interval = SmsSendTimer.Interval;
            SmsReadAndProcTimer.Interval = SmsReadAndProcTimer.Interval;
            NextSendingTime = DateTime.Now.AddMilliseconds(SmsSendTimer.Interval);
            NextReadingTime = DateTime.Now.AddMilliseconds(SmsReadAndProcTimer.Interval);
        }

        public void StopTimers()
        {
            SmsSendTimer.Stop();
            SmsReadAndProcTimer.Stop();
        }

        public void SmsReadAndProcTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                NextReadingTime = DateTime.Now.AddMilliseconds(SmsReadAndProcTimer.Interval);
                DoReadAndProc();
            }
            catch (Exception ex)
            {
                Log(ex.StackTrace);
            }
        }
        string[] dateformats = { "yyyyMMdd", "yyyy.MM.dd", "yyyy.M.d", "yyyy-MM-dd", "yyyy-M-d", "yyyy年MM月dd日", "yyyy年M月d日", "yyyy MM dd", "yyyy M d" };
        DateTime TimeZero = new DateTime(2000, 1, 1);
        public void DoReadAndProc()
        {
            DateTime Now = DateTime.Now;
            using (var DB = new Models.SiteDb())
            {
                //循环处理收到的短信 需要处理的
                var newSms = DB.SmsReceiveds.Where(v => v.ProcStatus != "已处理" && v.ProcStatus != "无法处理");
                foreach (var srcSms in newSms.ToList())
                {
                    try
                    {
                        var user = DB.aspnet_Users.FirstOrDefault(v => v.MobileAlias == srcSms.SenderCode || ("86" + v.MobileAlias) == srcSms.SenderCode);
                        if (null == user)
                        {
                            srcSms.ProcStatus = "无法处理";
                            DB.SaveChanges();
                            continue;
                        }
                        //正在等待的那个SmsSession
                        var smssess = DB.QizSmsSessions.Where(v => v.UserID == user.UserId && v.SessionStatus == 1).FirstOrDefault();
                        if (null == smssess)
                        {
                            srcSms.ProcStatus = "无法处理";
                            DB.SaveChanges();
                            continue;
                        }
                        smssess.User = user;
                        //当前最新问题
                        var lastSSDIdx = smssess.QizSmsSessionDetails.Count == 0 ? -1 : smssess.QizSmsSessionDetails.Max(v => v.QizSmsSubjDefine.QizSubjectDefine.SortIdx);
                        //下一个问题就是这个答复对应的问题。
                        var newSSD = smssess.QizSmsSubjectMonthIdx.QizSmsSubjDefines.Where(v => v.QizSubjectDefine.SortIdx > lastSSDIdx).OrderBy(v => v.QizSubjectDefine.SortIdx).FirstOrDefault();

                        //将结果写入SmsSessDetail
                        #region 将结果写入SmsSessDetail
                        EnumValue selv = null;
                        List<EnumValue> selvs = new List<EnumValue>();
                        var userv = srcSms.TextMessage;//TODO:如果有格式，做解析
                        string answer = null;
                        string selectionValue = null;
                        string autoeval = null;

                        #region 开始处理结果
                        bool isTimemarkSms = false; 
                        try
                        {
                            if (string.IsNullOrWhiteSpace(userv)) throw new ArgumentException("无法处理");

                            isTimemarkSms = (newSSD == null && smssess.Timemark == TimeZero);
                            //没有待回答问题，这个答复可能是检查时间。

                            if (isTimemarkSms)
                            {
                                DateTime dt = DateTime.Now;
                                if (!DateTime.TryParseExact(userv, dateformats, new System.Globalization.CultureInfo("zh-CN"), System.Globalization.DateTimeStyles.None, out dt))
                                {
                                    throw new ArgumentException("无法处理");
                                }
                                else
                                {
                                    smssess.Timemark = dt;
                                    DB.SaveChanges();
                                }
                            }
                            else
                            {


                                if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "4" || newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "5")
                                {
                                    foreach (var a in userv.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
                                    {
                                        var sTemp = newSSD.QizSubjectDefine.QizItem.EnumDefine.EnumValues.FirstOrDefault(v => v.EnumValID == a || v.OptionValue == a || v.OptionTitle == a);
                                        if (null == sTemp)
                                        {
                                            srcSms.ProcStatus = "无法处理";
                                            DB.SaveChanges();
                                            break;
                                        }
                                        selvs.Add(sTemp);
                                        answer = sTemp.EnumValID;
                                        selectionValue += sTemp.OptionTitle + ",";
                                    }
                                    if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "4" && selvs.Count > 1)
                                    {
                                        srcSms.ProcStatus = "无法处理";
                                    }
                                    if (srcSms.ProcStatus == "无法处理")
                                    {
                                        throw new ArgumentException("无法处理");
                                        //continue;
                                    }
                                    if (!string.IsNullOrWhiteSpace(answer))
                                    {
                                        selectionValue = selectionValue.TrimEnd(',');
                                        answer = answer.TrimEnd(',');
                                    }
                                }

                                if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "4" || newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "5")
                                {
                                    if (string.IsNullOrEmpty(newSSD.QizSubjectDefine.ThresholdLow))
                                    {
                                        autoeval = null;
                                    }
                                    else
                                    {
                                        var normals = newSSD.QizSubjectDefine.ThresholdLow.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                        if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "4")
                                        {
                                            autoeval = selvs.Any(s => normals.Contains(s.EnumValID)) ? null : "异常";
                                        }
                                        if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "5")
                                        {
                                            bool islower = normals.Any(a => selvs.Any(s => s.EnumValID == a));
                                            bool isUp = selvs.Any(s => normals.Contains(s.EnumValID));
                                            autoeval = (islower && isUp) ? null : "异常";
                                        }
                                    }
                                }
                                else if (newSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue == "2")
                                {
                                    double v = 0, vl = 0, vh = 0;
                                    if (!double.TryParse(userv, out v)) throw new ArgumentException("无法处理");

                                    if (double.TryParse(newSSD.QizSubjectDefine.ThresholdLow, out vl) && double.TryParse(newSSD.QizSubjectDefine.ThresholdHight, out vh))
                                    {
                                        autoeval = (v >= vl && v <= vh) ? null : "异常";
                                    }
                                }
                                //if (!autosessioneval && autoeval != null) autosessioneval = true;
                            }
                        }
                        catch (ArgumentException aex)
                        {
                            if (aex.Message == "无法处理")
                            {
                                srcSms.ProcStatus = "无法处理";
                                #region 发送无法处理提醒
                                string textMessage = "答案格式错误，请重新答复。";
                                var errorMsg = DB.SiteCfgs.FirstOrDefault(s => s.ID == "errorMessage");
                                if (errorMsg != null)
                                {
                                    textMessage = errorMsg.Value;
                                }
                                var ss = new Models.SmsSent()
                                {
                                    ID = DB.NewID(),
                                    ReceiverCode = user.MobileAlias,
                                    ReceiverName = user.UserName,
                                    SenderCode = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.DoctorID.ToString(),
                                    SenderName = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.aspnet_Users.UserName,
                                    SentTime = Now,
                                    SmsType = "短信随访",
                                    ProcStatus = "发送",
                                    ProcTime = Now,
                                    TextMessage = textMessage
                                };

                                DB.SmsSents.AddObject(ss);
                                DB.SaveChanges();
                                #endregion
                                continue;
                            }
                            else
                                throw aex;
                        }
                        #endregion

                        if (!isTimemarkSms) smssess.QizSmsSessionDetails.Add(new QizSmsSessionDetail { Timemark = srcSms.SentTime.Value, ValueAutoEvalution = autoeval, ID = DB.NewID(), QizSmsSubjDefine = newSSD, UserValue = string.IsNullOrWhiteSpace(selectionValue) ? userv : selectionValue, UserSelValueID = answer, EnumValue = selv });

                        #endregion

                        srcSms.ProcStatus = "已处理";
                        srcSms.ProcTime = Now;
                        DB.SaveChanges();
                        //寻找下一个问题
                        var NextSSD = isTimemarkSms ? null : smssess.QizSmsSubjectMonthIdx.QizSmsSubjDefines.Where(v => v.QizSubjectDefine.SortIdx > newSSD.QizSubjectDefine.SortIdx && v.QizSubjectDefine.QizItem.TypeRef.OptionValue != "7").OrderBy(v => v.QizSubjectDefine.SortIdx).FirstOrDefault();
                        if (null != NextSSD)
                        {
                            #region 发送下一个问题
                            var ss = new Models.SmsSent()
                            {
                                ID = DB.NewID(),
                                ReceiverCode = user.MobileAlias,
                                ReceiverName = user.UserName,
                                SenderCode = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.DoctorID.ToString(),

                                SenderName = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.aspnet_Users.UserName,
                                SentTime = Now,
                                SmsType = "短信随访",
                                ProcStatus = "发送",
                                ProcTime = Now,
                                TextMessage = NextSSD.QizSubjectDefine.QizItem.Title//TODO:短信随访的格式。--各种类型的。
                            };
                            ConvertMessage(NextSSD, ss);
                            DB.SmsSents.AddObject(ss);
                            DB.SaveChanges();
                            #endregion
                            continue;
                        }
                        //如果此session没有 数据时间，则询问数据时间，否则，即已经完成随访。
                        else if (!isTimemarkSms)// smssess.Timemark==DateTime.MinValue){
                        {
                            #region 发送----检查时间问题
                            var ss = new Models.SmsSent()
                            {
                                ID = DB.NewID(),
                                ReceiverCode = user.MobileAlias,
                                ReceiverName = user.UserName,
                                SenderCode = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.DoctorID.ToString(),

                                SenderName = smssess.QizSmsSubjectMonthIdx.QizSmsSubject.aspnet_Users.UserName,
                                SentTime = Now,
                                SmsType = "短信随访",
                                ProcStatus = "发送",
                                ProcTime = Now,
                                TextMessage = "请答复上述内容的检查日期____。格式例如：20130508"
                            };
                            //ConvertMessage(NextSSD, ss);
                            DB.SmsSents.AddObject(ss);
                            DB.SaveChanges();

                            #endregion
                            continue;
                        }
                        else
                        {
                            //没有下一个问题，，本随访完成。
                            smssess.SessionStatus = 3;
                            smssess.SessionAutoEvalution = smssess.QizSmsSessionDetails.Any(v => v.ValueAutoEvalution == "异常") ? "异常" : "正常";
                            DB.SaveChanges();
                            Controllers.Services svc = new Controllers.Services();
                            svc.DB = DB;
                            svc.SessionEvalStatusNotify(smssess);
                            //此人的其他随访
                            //FindTodaysSmsSuiFangEventAndSendOneForUser(DB, user, DateTime.Now);
                            ProcTodaysReminding(DB, user, DateTime.Now,true);
                            continue;

                        }
                    }
                    catch (Exception ex)
                    {
                        Log(ex.ToString());
                    }
                }

            }
        }

        /// <summary>
        /// 生成用于发送的 格式良好的短信，从 QizSmsSubjDefine。
        /// 根据不同类型，分别硬编码出格式。
        /// </summary>
        /// <param name="NextSSD"></param>
        /// <param name="ss"></param>
        protected void ConvertMessage(QizSmsSubjDefine NextSSD, SmsSent ss)
        {
            var msgformat = string.Empty;

            var ovQizItemType = NextSSD.QizSubjectDefine.QizItem.TypeRef.OptionValue;
            if (ovQizItemType == "4" || ovQizItemType == "5")
            {
                var tempstr = string.Join("，", NextSSD.QizSubjectDefine.QizItem.EnumDefine.EnumValues.Select(v => v.OptionValue + "：" + v.OptionTitle).ToArray());
                var msstr = (ovQizItemType == "5") ? "，多选以空格隔开。" : string.Empty;
                msgformat = "请完成下述随访“" + ss.TextMessage + "？" + tempstr + "”，直接回复编号___" + msstr;
                ss.TextMessage = msgformat;
            }
            else if (ovQizItemType == "6")
            {
                msgformat = "请完成下述随访“" + ss.TextMessage + "？”，如果有检查，请将检查结果扫描或拍照后，登录www.3AB.com.cn进行网上上传！\r\n回复 1 继续随访。";
                ss.TextMessage = msgformat;
            }
            else
            {
                //msgformat = "您好，请完成下述随访“" + ss.TextMessage + "？”，回复" + NextSSD.QizSubjectDefine.QizItem.TypeRef.OptionTitle + "格式短信“答案”。 ";
                msgformat = "请完成下述随访“" + ss.TextMessage + "？”，直接回复" + NextSSD.QizSubjectDefine.QizItem.TypeRef.OptionTitle + "___";
                if (ovQizItemType != "3")
                {
                    //msgformat += (string.IsNullOrEmpty(NextSSD.QizSubjectDefine.QizItem.Unit) ? "" : "单位：") + NextSSD.QizSubjectDefine.QizItem.Unit;
                    //msgformat += NextSSD.QizSubjectDefine.QizItem.Unit;
                }
                else
                {
                    //msgformat += ", 例如20120819";
                }
                ss.TextMessage = msgformat;
            }
        }

        public void SmsSendTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                SmsSendTimer.Interval = Hour24.TotalMilliseconds;
                NextSendingTime = DateTime.Now.AddMilliseconds(SmsSendTimer.Interval);
                DoSmsSend();
            }
            catch (Exception ex)
            {
                Log(ex.StackTrace);
            }
        }
        protected aspnet_Users adminUser;

        public void DoSmsSend()
        {
            DateTime Now = DateTime.Now;

            bool mockuserflag = false;
            if (Debug_IsMocking)
            {
                Debug_IsMocking = false;
                mockuserflag = true;
                Now = Debug_MockNowValue;
            }



            DateTime NowHoured = Now.Date.AddHours(Now.Hour);
            DateTime YesHour = NowHoured.AddDays(-1);
            DateTime YesHour2 = NowHoured.AddDays(-2);


            using (var DB = new Models.SiteDb())
            {
                adminUser = DB.aspnet_Roles.FirstOrDefault(v => v.RoleName == "Admin").aspnet_Users.First();

                #region send smsquiz if recuper not submit a qizsession in this month-idx

                Log("更新SmsSession[过期]状态。1来更新状态，2来，便于后续，计算。");

                foreach (var expiredSmsSes in DB.QizSmsSessions.Where(v => v.SessionStatus == 1 && v.CreationTime <= YesHour2))
                {
                    Log("\t", expiredSmsSes.ID, expiredSmsSes.QizSmsSubjectMonthIdx.MonthIdx.ToString(), expiredSmsSes.QizSmsSubjectMonthIdx.LastMonthIdx.ToString(), expiredSmsSes.QizSmsSubjectMonthIdx.QizSmsSubject.Title);
                    expiredSmsSes.SessionStatus = 2;
                }
                DB.SaveChanges();

                Log("所有正在等其回复的SmsSes的用户");
                var SkipedUserIDs = DB.QizSmsSessions.Where(v => v.SessionStatus == 1).Select(v => v.UserID).Distinct().ToArray();
                Log(SkipedUserIDs.Select(v => v.ToString()).ToArray());

                Log("所有没有在等回复的用户,候选用户。");
                var targetUserList = DB.QizSubjectObjForDoctors.Select(v => v.Recuper.User).Distinct()//所有用户中...
                    .Where(v => !SkipedUserIDs.Contains(v.UserId)).ToList();//...不再等待回复的用户列表

                Log<string>(() => targetUserList.Select(v => v.UserName));
                bool Debug_ForceDebugUser = false;
                if (Debug_ForceDebugUser)
                {
                    var debuguser = DB.aspnet_Users.First(v => Debug_MockUserNames.Contains(v.UserName));
                    ProcTodaysReminding(DB, debuguser, Now,false);
                }
                else
                {
                    foreach (var user in targetUserList.ToArray())
                    {
                        try
                        {
                            if (mockuserflag)
                            {
                                if (!Debug_MockUserNames.Contains(user.UserName)) continue;
                            }
                            try
                            {
                                Log("随意选取一个 还没参与的SesSubj---用户是" + user.UserName);
                                ProcTodaysReminding(DB, user, Now,false);
                                //FindTodaysSmsSuiFangEventAndSendOneForUser(DB, user, Now);
                            }
                            catch (Exception ex)
                            {
                                Log(ex.StackTrace);
                            }
                        }
                        catch (Exception ex)
                        {
                            Log(ex.Message, ex.StackTrace);
                        }
                    }
                }
                mockuserflag = false;

                #endregion

            }
        }
        ///// <summary>
        ///// 为指定用户 找到需要今天处理的随访QizSessionReminding，并发送其中一个。
        ///// 这个方法只发送第一条，再接收处理方法DoReadAndProc里会处理剩余的问题，并在结束后继续为这个用户发送他的其他需要今天处理的随访。
        ///// QizSessionReminding.TaskType==随访 的。
        ///// </summary>
        ///// <param name="DB"></param>
        ///// <param name="user"></param>
        ///// <param name="Now"></param>
        //private void FindTodaysSmsSuiFangEventAndSendOneForUser(SiteDb DB, aspnet_Users user, DateTime Now)
        //{
        //    var today = Now.Date;

        //    //获取此用户，所有参加的随访/短信随访，然后，因为每天发送一次短信，所以，不用管阶段，只看，现在时间是在发短信的那一天，就可以识别出需要发送短信。
        //    QizSubjectObjForDoctor tempSuifang = null;
        //    Recuper tempRecuper = null;
        //    QizSessionReminding tempReminding = null;

        //    Log("查找是否有需要处理的催报或随访。");
        //    foreach (var suifang in DB.QizSubjectObjForDoctors.Where(v => v.Recuper.UserID == user.UserId && v.QizSmsSubject != null).ToArray())
        //    {
        //        try
        //        {
        //            tempSuifang = suifang;
        //            tempRecuper = suifang.Recuper;
        //            DateTime dehospitalday = tempRecuper.DeHospDay.Date;

        //            var tempReminding_temp =
        //                //此随访的短信随访定义的所有阶段里还没有填报过的阶段，所包含的提醒设定里...
        //                //suifang.QizSmsSubject.QizSmsSubjectMonthIdxes.Where(v => v.QizSmsSessions.Count == 0 && v.QizSmsSubject.QizSubject.QizSessions.Count == 0)
        //                suifang.QizSmsSubject.QizSmsSubjectMonthIdxes.Where(v => !v.QizSmsSessions.Any(s => s.UserID == user.UserId) && !v.QizSmsSubject.QizSubject.QizSessions.Any(s => s.UserID == user.UserId))
        //                //选一个今天需要提醒的
        //                .SelectMany(v => v.QizSessionRemindings).Where(v => v.TaskEnabled == "启用" && v.TaskType == "随访").ToList();

        //            tempReminding = tempReminding_temp.FirstOrDefault(v => dehospitalday.AddMonths(v.MonthOffset - 1).AddDays(v.DayOffset - 1) == today);

        //            //找到就跳出。//否则继续看下一个随访
        //            if (null != tempReminding) break;
        //        }
        //        catch (Exception ex)
        //        {
        //            Log(ex.StackTrace);
        //        }
        //    }

        //    //如果最后没找到，则这个人没有要处理的内容。return.及继续下一个人。
        //    if (null == tempReminding)
        //    {
        //        Log("这个人没有要处理的内容。return.及继续下一个人。");
        //        return;
        //    }

        //    Log("处理这个纪录。"); Log(tempRecuper.Hospital.HospName, tempRecuper.BingQu.Title, tempRecuper.Department.DepName, tempRecuper.DeHospDay.ToString("yyyy-MM-dd")); Log(tempReminding.TaskType.ToString(), tempReminding.QizSmsMonthIdxID, tempReminding.MonthOffset.ToString(), tempReminding.DayOffset.ToString());

        //    SendSuifang(DB, tempReminding, tempRecuper, Now);

        //}

        /// <summary>
        /// 为指定用户的所有住院信息 找到今天的需要催报和随访的QizSessionReminding记录，并发送所有的催报。
        /// QizSessionReminding.TaskType==随访 的。
        /// </summary>
        /// <param name="DB"></param>
        /// <param name="user"></param>
        /// <param name="Now"></param>
        private void ProcTodaysReminding(SiteDb DB, aspnet_Users user, DateTime Now,bool SuifangOnly)
        {
            var today = Now.Date;

            //获取此用户，所有参加的随访/短信随访，然后，因为每天发送一次短信，所以，不用管阶段，只看，现在时间是在发短信的那一天，就可以识别出需要发送短信。

            Log("查找是否有需要处理的催报或随访。");
            QizSessionReminding tempQizSessionRemindingforsuifang = null;
            Recuper tempRecuperforsuifang = null;
            foreach (var suifang in DB.QizSubjectObjForDoctors.Where(v => v.Recuper.UserID == user.UserId && v.QizSmsSubject != null).ToArray())
            {
                try
                {
                    Log(suifang.Recuper.User.UserName, suifang.Recuper.RecuperID, suifang.QizSubject.Title, suifang.QizSmsSubject.Title);
                    DateTime dehospitalday = suifang.Recuper.DeHospDay.Date;

                    var moff = (Now.Year - dehospitalday.Year) * 12 + (Now.Month - dehospitalday.Month) + (Now.Day < dehospitalday.Day ? 0 : 1);//今天是在“第几个月”base 1
                    var doff = (today - dehospitalday.AddMonths(moff-1)).Days;

                    if (moff < 1)
                    {
                        Log("可能没出院");
                        continue;
                    }

                    Log("计算这个随访今天的催报和短信");
                    var rmsall = DB.QizSessionRemindings.Where(v => v.QizSmsSubjectMonthIdx.QizSmsSubjectID == suifang.QizSmsSubjectID && v.TaskEnabled == "启用" && (v.MonthOffset == moff && v.DayOffset == doff)).ToList();

                    //var rmssui = curmidx.QizSessionRemindings.Where(v => v.QizSmsSubjectMonthIdx.QizSmsSubjectID == suifang.QizSmsSubjectID && v.TaskEnabled == "启用" && v.TaskType == "随访" && dehospitalday.AddMonths(v.MonthOffset - 1).AddDays(v.DayOffset - 1) == today).ToList();
                    //var rmscui = curmidx.QizSessionRemindings.Where(v => v.TaskEnabled == "启用" && v.TaskType == "催报" && dehospitalday.AddMonths(v.MonthOffset - 1).AddDays(v.DayOffset - 1) == today).ToList();

                    if (rmsall.Count == 0)
                    {
                        Log("这个随访今天无催报和短信");
                        continue;
                    }

                    foreach (var curmidx in rmsall.Select(v => v.QizSmsSubjectMonthIdx).Distinct())
                    {
                        var rmscui = rmsall.Where(v => v.TaskType == "催报" && v.QizSmsMonthIdxID == curmidx.ID).ToList();
                        var rmssui = rmsall.Where(v => v.TaskType == "随访" && v.QizSmsMonthIdxID == curmidx.ID).ToList();

                        var midxDateS = dehospitalday.Date.AddMonths(curmidx.LastMonthIdx);
                        var midxDateE = dehospitalday.Date.AddMonths(curmidx.MonthIdx).AddDays(1);

                        var hasData = (DB.QizSmsSessions.Any(v => v.RecuperID == suifang.RecuperID && v.CreationTime >= midxDateS && v.CreationTime < midxDateE && v.QizSmsSubjectMonthIdx.QizSmsSubjectID == suifang.QizSmsSubjectID)
                            || DB.QizSessions.Any(v => v.RecuperID == suifang.RecuperID && v.CreationTime >= midxDateS && v.CreationTime < midxDateE && v.QizSubjectID == suifang.QizSubjectID));

                        if (hasData)
                        {
                            Log("已经参与过，不用处理");
                            continue;
                        }

                        foreach (var item in rmssui)
                        {

                            Log("发现一个短信随访,记录之。"); Log(suifang.Recuper.Hospital.HospName, suifang.Recuper.BingQu.Title, suifang.Recuper.Department.DepName, suifang.Recuper.DeHospDay.ToString("yyyy-MM-dd")); Log(item.TaskType.ToString(), item.QizSmsMonthIdxID, item.MonthOffset.ToString(), item.DayOffset.ToString());
                            if (null == tempQizSessionRemindingforsuifang)
                            {
                                tempQizSessionRemindingforsuifang = item;
                                tempRecuperforsuifang = suifang.Recuper;
                            }
                            //SendSuifang(DB, item, suifang.Recuper, Now);
                            continue;
                        }

                        if (!SuifangOnly)
                        {
                            foreach (var item in rmscui)
                            {
                                SendReminding(DB, item, suifang.Recuper, Now, suifang.Doctor);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log(ex.StackTrace);
                }

            }
            //先发完所有催报，才开始随访。因为随访同时只有一个在进行。后续的在收到短信并处理的逻辑里。
            if (null != tempQizSessionRemindingforsuifang)
            {
                SendSuifang(DB, tempQizSessionRemindingforsuifang, tempRecuperforsuifang, Now);
            }



        }
        protected void SendReminding(SiteDb DB, QizSessionReminding reminding, Recuper recu, DateTime Now, aspnet_Users sender)
        {
            //using (var DB = new Models.SiteDb())
            //{
            Log("发催报[随访通知]给" + recu.User.MobileAlias);
            var ss = new Models.SmsSent()
            {
                ID = DB.NewID(),
                ReceiverCode = recu.User.MobileAlias,
                ReceiverName = recu.User.UserName,
                SenderCode = sender.UserId.ToString(),
                SenderName = sender.UserName,
                SentTime = Now,
                SmsType = "随访通知",
                ProcStatus = "发送",
                ProcTime = Now,
                TextMessage = reminding.TextContent
            };
            DB.SmsSents.AddObject(ss);
            DB.SaveChanges();
            Log("完成催报。");
            //}
        }
        protected void SendSuifang(SiteDb DB, QizSessionReminding reminding, Recuper recu, DateTime Now)
        {
            //using (var DB = new Models.SiteDb())
            //{
            Models.QizSmsSession smsses = null;
            #region 开始短信随访
            Log("记录短信随访session" + recu.User.UserName + "," + recu.User.MobileAlias);
            smsses = new Models.QizSmsSession()
            {
                ID = DB.NewID(),
                QizSmsSubjectMonthIdxID = reminding.QizSmsMonthIdxID,
                Timemark = TimeZero,
                CreationTime = Now,
                //User = recu.User,
                UserID = recu.UserID,
                RecuperID = recu.RecuperID,
                SubmitSrc = "短信",
                UnRead=true,
                SessionStatus = 1
            };
            DB.QizSmsSessions.AddObject(smsses);

            Log("开始发随访");
            var subjDef = reminding.QizSmsSubjectMonthIdx.QizSmsSubjDefines.OrderBy(v => v.QizSubjectDefine.SortIdx).First();

            var smssent = new Models.SmsSent()
            {
                ID = DB.NewID(),
                ReceiverCode = recu.User.MobileAlias,
                ReceiverName = recu.User.UserName,
                SenderCode = reminding.QizSmsSubjectMonthIdx.QizSmsSubject.DoctorID.ToString(),
                SenderName = reminding.QizSmsSubjectMonthIdx.QizSmsSubject.aspnet_Users.UserName,
                SentTime = Now,
                SmsType = "短信随访",
                ProcStatus = "发送",
                ProcTime = Now,
                TextMessage = subjDef.QizSubjectDefine.QizItem.Title//TODO:短信随访的格式。--各种类型的。
            };
            ConvertMessage(subjDef, smssent);
            var yindaoyu = reminding.QizSmsSubjectMonthIdx.QizSmsSubject.SmsYinDaoYue;
            yindaoyu = yindaoyu == null ? string.Empty : (yindaoyu + "\r\n");
            smssent.TextMessage = yindaoyu + smssent.TextMessage;

            DB.SmsSents.AddObject(smssent);
            DB.SaveChanges();
            Log("记录session和发随访完成。回复后会继续随访。");
            //}
            #endregion
        }

        #region IDisposable 成员

        public void Dispose()
        {
            StopTimers();
            SmsSendTimer.Dispose();
            SmsReadAndProcTimer.Dispose();
        }

        #endregion
    }
}